/*
 Copyright (C) 2009 QDSS.org
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.qdss.topisv.api;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Api调用者
 * 
 * @author <a href="mailto:zhaofang123@gmail.com">FANGFANG ZHAO</a>
 * @since 0.1.0, Nov 17, 2009
 * @version $Id: ApiInvoker.java 69 2012-09-07 17:18:03Z zhaofang123 $
 */
public class ApiInvoker implements Serializable {
	private static final long serialVersionUID = -1656867805727399869L;

	private static final Log LOG = LogFactory.getLog(ApiInvoker.class);
	
	final private HttpClientFetcher httpClientFetcher;
	final protected String apiUrl;
	final protected Map<String, String> sysParameters;
	
	/**
	 * @param appKey
	 * @param appSecret
	 */
	public ApiInvoker(String appKey, String appSecret) {
		this(appKey, appSecret, ApiUtils.REST_URL);
	}
	
	/**
	 * @param appKey
	 * @param appSecret
	 * @param apiUrl
	 */
	public ApiInvoker(String appKey, String appSecret, String apiUrl) {
		Map<String, String> sp = new HashMap<String, String>();
		sp.put(ApiUtils.SP_APP_KEY, appKey);
		sp.put(ApiUtils.SP_APP_SECRET, appSecret);
		sp.put("format", "xml");
		sp.put("sign_method", "md5");
		sp.put("v", "2.0");
		this.sysParameters = Collections.unmodifiableMap(sp);
		LOG.warn("Initialization app " + appKey);
		
		this.apiUrl = apiUrl;
		this.httpClientFetcher = new HttpClientFetcher();
	}
	
	/**
	 * 获取APP_KEY
	 * 
	 * @return
	 */
	final public String getAppKey() {
		return sysParameters.get(ApiUtils.SP_APP_KEY);
	}
	
	/**
	 * 获取APP_SECRET
	 * 
	 * @return
	 */
	final public String getAppSecret() {
		return sysParameters.get(ApiUtils.SP_APP_SECRET);
	}
	
	/**
	 * 获取系统级参数
	 * 
	 * @return
	 */
	public Map<String, String> getSysParameters() {
		Map<String, String> params = new HashMap<String, String>(sysParameters);
		params.put(ApiUtils.SP_TIMESTAMP, 
				new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance(Locale.CHINA).getTime()));
		return params;
	}
	
	/**
	 * 获取系统级参数, 并且指定API名称
	 * 
	 * @param apiName
	 * @return
	 */
	public Map<String, String> getSysParameters(String apiName) {
		Map<String, String> params = getSysParameters();
		params.put(ApiUtils.SP_METHOD, apiName);
		return params;
	}
	
	/**
	 * 获取系统级参数, 并且指定API名称及认证SESSION
	 * 
	 * @param apiName
	 * @param session
	 * @return
	 */
	public Map<String, String> getSysParameters(String apiName, String session) {
		Map<String, String> params = getSysParameters(apiName);
		params.put(ApiUtils.SP_SESSION, session);
		return params;
	}
	
	/**
	 * 调用<tt>GET</tt>方法
	 * 
	 * @param params
	 * @return
	 */
	public Result invoke(Map<String, String> params) {
		return invokeGet(params, false);
	}
	
	/**
	 * 调用<tt>GET</tt>方法
	 * 
	 * @param params
	 * @param isGzip
	 * @return
	 */
	public Result invoke(Map<String, String> params, boolean isGzip) {
		return invokeGet(params, isGzip);
	}
	
	/**
	 * 调用<tt>GET</tt>方法
	 * 
	 * @param params
	 * @return
	 */
	public Result invokeGet(Map<String, String> params) {
		return invokeGet(params, false);
	}
	
	/**
	 * 调用<tt>POST</tt>方法
	 * 
	 * @param params
	 * @return
	 */
	public Result invokePost(Map<String, String> params) {
		return invokePost(params, Collections.<String>emptySet(), false);
	}
	
	/**
	 * 调用<tt>POST</tt>方法
	 * 
	 * @param params
	 * @param isGzip
	 * @return
	 */
	public Result invokePost(Map<String, String> params, boolean isGzip) {
		return invokePost(params, Collections.<String>emptySet(), isGzip);
	}
	
	/**
	 * 调用<tt>POST</tt>方法, 可选择指定大文本参数名称
	 * 
	 * @param params
	 * @param longtextParams
	 * @return
	 */
	public Result invokePost(Map<String, String> params, String longtextParamName) {
		return invokePost(params, longtextParamName, false);
	}
	
	/**
	 * 调用<tt>POST</tt>方法, 可选择指定大文本参数名称
	 * 
	 * @param params
	 * @param longtextParams
	 * @param isGzip
	 * @return
	 */
	public Result invokePost(Map<String, String> params, String longtextParamName, boolean isGzip) {
		Set<String> set = null;
		if (longtextParamName != null) {
			set = new HashSet<String>(1);
			set.add(longtextParamName);
		}
		return invokePost(params, set, isGzip);
	}
	
	/**
	 * 调用<tt>POST</tt>方法, 可选择指定大文本参数名称集合
	 * 
	 * @param params
	 * @param longtextParams
	 * @param isGzip
	 * @return
	 */
	public Result invokePost(Map<String, String> params, Set<String> longtextParamNames) {
		return invokePost(params, longtextParamNames, false);
	}
	
	// --
	
	/**
	 * 调用<tt>GET</tt>方法
	 * 
	 * @param params
	 * @param isGzip
	 * @return
	 */
	public Result invokeGet(Map<String, String> params, boolean isGzip) {
		final String uri = ApiUtils.toApiInvokeURI(this.apiUrl, params, null);
		HttpMethod method = new GetMethod(uri);
		if (isGzip) {
			method.addRequestHeader("Accept-Encoding", "gzip, deflate");
		}
		
		Result result = getHttpClientFetcher().executeMethod(method);
		return result;
	}
	
	/**
	 * 调用<tt>POST</tt>方法, 可选择指定大文本参数名称集合
	 * 
	 * @param params
	 * @param longtextParams
	 * @param isGzip
	 * @return
	 */
	public Result invokePost(Map<String, String> params, Set<String> longtextParamNames, boolean isGzip) {
		final String uri = ApiUtils.toApiInvokeURI(this.apiUrl, params, longtextParamNames);
		PostMethod method = new PostMethod(uri);
		if (longtextParamNames != null) {
			for (String p : longtextParamNames) {
				String v = params.get(p);
				if (v != null) {
					method.setParameter(p, v);
				}
			}
		}		
		if (isGzip) {
			method.addRequestHeader("Accept-Encoding", "gzip, deflate");
		}
		
		Result result = getHttpClientFetcher().executeMethod(method);
		return result;
	}
	
	/**
	 * 获取HttpClientFetcher
	 * 
	 * @return
	 */
	public HttpClientFetcher getHttpClientFetcher() {
		return httpClientFetcher;
	}
	
	@Override
	public String toString() {
		return super.toString() +
				"#[APP=" + sysParameters.get(ApiUtils.SP_APP_KEY) + "; URL=" + this.apiUrl + "]";
	}
}